/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package models;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;

import controllers.Security;
import play.db.jpa.Model;

/**
 * 
 * @author Ousama
 */
@Entity
public class Organizer extends Model {
	@ManyToOne
	public IdeaDeveloper ideaDeveloper;
	@ManyToMany(cascade = CascadeType.ALL)
	public List<Entities> manages = new ArrayList<Entities>();
	@ManyToMany
	public List<Topic> managedTopics = new ArrayList<Topic>();
	@ManyToMany
	public List<ActionPlan> managedActionPlane = new ArrayList<ActionPlan>();
	@ManyToMany
	public List<ActionItem> managedActionItem = new ArrayList<ActionItem>();

	/**
	 * @author Ousama
	 * @param dev
	 *            the developer i will make an organizaer for
	 * @return the organizer i just saved
	 */
	public static Organizer create(IdeaDeveloper dev) {
		Organizer orgz = new Organizer();
		orgz.ideaDeveloper = dev;
		orgz.save();

		Log log = new Log("^ is now an organizer.");
		log.ids = dev.id + "";
		log.types = "developer";
		log.save();

		return orgz;

	}

	/**
	 * Helper method that deletes the organizaer an all its components
	 */
	public void delete2() {
		// not a manager anymore
		for (int i = 0; i < managedActionItem.size(); i++) {
			managedActionItem.get(i).managers.remove(this);
			managedActionItem.get(i).save();
		}
		// deleting the manager from the managed entities
		for (int i = 0; i < manages.size(); i++) {
			manages.get(i).managers.remove(this);
			manages.get(i).save();
		}
		// delting being manager for topics
		for (int i = 0; i < managedTopics.size(); i++) {
			managedTopics.get(i).managers.remove(this);
			managedTopics.get(i).save();
		}

		// not a manager for the actionbplane anymore
		for (int i = 0; i < managedActionPlane.size(); i++) {
			managedActionPlane.get(i).managers.remove(this);
			managedActionPlane.get(i).save();
		}
		

		Log log = new Log("^ is no longer an organizer.");
		log.ids = this.id + "";
		log.types = "organizer";
		log.save();
                this.delete();

	}

	/**
	 * allows the Organizer to Send invitation to any Idea Developer to join the
	 * Entity which organizer on
	 * 
	 * @author OmarKhaled
	 * @param entity
	 *            the entity which the user is invited to
	 * @param invitedUser
	 *            the user which the invitation is sent to
	 * @param typeOfRequest
	 *            the type of the invitation and its by default here
	 *            "JoinEntFromEntToDev" because the entity is sending the
	 *            invitation to the idea developer
	 * @return the Request sent from the entity to the invited user
	 */
	public static Request inviteIdeaDeveloperToEntity(Entities entity,
			IdeaDeveloper invitedUser, String typeOfRequest) {
		typeOfRequest = "JoinEntFromEntToDev";
		return Request.RequestMe(entity, invitedUser, typeOfRequest);
	}

	/**
	 * allows organizer to invite any idea developer to become Organizer on the
	 * Entity which organizer on
	 * 
	 * @author OmarKhaled
	 * @param entity
	 *            the entity which the user is invited to
	 * @param invitedUser
	 *            the user which the invitation is sent to
	 * @param typeOfRequest
	 *            the type of the invitation and its by default here
	 *            "JoinEntFromEntToDev" because the entity is sending the
	 *            invitation to the idea developer
	 * @return
	 */
	public static Request invitationToBeOrganizer(Entities entity,
			IdeaDeveloper invitedUser, String typeOfRequest) {
		typeOfRequest = "JoinEntFromEntToDev";
		return Request.RequestMe(entity, invitedUser, typeOfRequest);
		// return Request.requestToBeOrganizer(entity,
		// invitedUser,typeOfRequest);
	}

	/**
	 * allows the organizer to create topic inside the entity which organize
	 * 
	 * @author OmarKhaled
	 * @param title
	 *            the name of the created entity
	 * @param description
	 *            the description of the topic
	 * @param entityId
	 *            the id of the entity where the topic is created
	 * @param ideaDeveloperId
	 *            the idea developer id of the organizer creating the topic
	 * @return the created Topic
	 */
	public static Topic createTopicEnt(String title, String description,
			long entityId, long ideaDeveloperId) {
		return Topic.createTopicEnt(title, description, entityId,
				ideaDeveloperId);
	}

	/**
	 * allows the organizer to create topic inside the organization
	 * 
	 * @author
	 * @param title
	 *            the title given to the topic
	 * @param description
	 *            the description of the topic
	 * @param organizationId
	 *            the organization where the topic lies
	 * @param ideaDeveloperId
	 *            the organizer creating the topic
	 * @return
	 */
	public static Topic createTopicOrg(String title, String description,
			long organizationId, long ideaDeveloperId) {
		return Topic.createTopicOrg(title, description, organizationId,
				ideaDeveloperId);
	}

	/**
	 * @author: Amr gamal This method assings requirments and status for a plan
	 * 
	 * @param actionPlan
	 *            is the action plan which the requirments and status will be
	 *            assigned to
	 * @param requirment
	 *            the requirment that will be assigned to the action plan
	 * 
	 * @param status
	 *            the status that will be assigned to the plan requirments or
	 *            status were set or the plan was already executed
	 */
	public String setPlanRequirmentsStatus(ActionPlan actionPlan,
			String requirment, String status) {
		Date currentDate = new Date();
		Date endDate = actionPlan.endDate;
		if (endDate.before(currentDate)) {
			// error msg ("Plan Already Executed")
			return "Plan Already Executed";
		} else {

			actionPlan.requirment = requirment;
			actionPlan.save();
			actionPlan.status = status;
			actionPlan.save();
			
			List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
			 toBeNotified.addAll(actionPlan.volunteers);
			  //NOTIFICATION
			  
			  for (int i = 0; i < toBeNotified.size(); i++) { 
			  Notification.notify(" has edit the requirments and status of the actionPlan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
					+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(i), this.ideaDeveloper, currentDate); }
			
            
			Log log = new Log("^ set ^ requirments to " + requirment
					+ " and status to " + status);
			log.ids = this.id + "," + actionPlan.id;
			log.types = "organizer,actionplan";
			log.save();

			return "Done";
			// notify actionPlan followers
			// notification or popup window for successful assigning
		}

	}

	/**
	 * Allows the organizer to start an action plan
	 * 
	 * @author Doaa Ramiz
	 * 
	 * @param String
	 *            name, the name of the action plan
	 * @param Idea
	 *            idea, the idea that the organizer wanted to start an action
	 *            plan with
	 * @param String
	 *            body, the body of the action plan
	 * @param Date
	 *            startDate, the start date of the action plan
	 * @param Date
	 *            endDate, the end date of the action plan
	 * @return string of a msg that the action plan started or an error msg
	 * 
	 */
	public String startActionPlan(String name, Idea i, String description,
			Date startDate, Date endDate) {

		long count = ActionPlan.count("name = ?", name);
		Date today = new Date();

		if (count == 0) {

			if (!i.promotedForExecution) {

				return "Sorry, this idea is not promoted for execution";

			} else {

				if (startDate.after(endDate)) {

					return "Sorry, end date can not precede start date";

				} else {

					if (today.after(startDate)) {

						return "Sorry, stat date can not precede today";

					} else {

						ActionPlan ap = new ActionPlan();

						ap.name = name;
						ap.save();
						ap.ideas.add(i);
						ap.save();
						ap.description = description;
						ap.save();
						ap.startDate = startDate;
						ap.save();
						ap.endDate = endDate;
						ap.save();
						ap.managers.add(this);
						ap.save();
						ap.organizationId = ap.getIdeasOrganization(i);
						ap.save();
						i.ideaPlan = ap;
						i.save();

						Log log = new Log("^ started ^ for executing ^");
						log.ids = this.id + "," + ap.id + "," + i.id;
						log.types = "Organizer,ActionPlan,Idea";
						log.save();

						if (!ap.getFollowers(i).isEmpty()) {

							List<IdeaDeveloper> followers = ap.getFollowers(i);

							for (int j = 0; j < followers.size(); j++) {

								IdeaDeveloper id = followers.get(j);
								Notification.notify(
										"has started a new action plan", id,
										this.ideaDeveloper, new Date());
							}
						}

						return "Action plan started";
					}
				}
			}

		} else {

			return "Sorry this name is not avaliable";
		}
	}

	/**
	 * This method blocks an ideaDeveloper from a certain entity
	 * 
	 * @author Maryam
	 * 
	 * @param ideaDeveloper
	 *            The ideaDeveloper who will be blocked
	 * @param entity
	 *            The entity that the ideaDeveloper will be blocked from
	 * 
	 * 
	 */
	public void blockIdeaDeveloper(IdeaDeveloper ideaDeveloper, Entities entity) {
		ideaDeveloper.blockedEnt.add(entity);
		entity.blocked.add(ideaDeveloper);
		Log log = new Log("^ is now blocked from ^.");
		log.ids = ideaDeveloper.id + "," + entity.id;
		log.types = "developer,entity";
		log.save();

	}

	/**
	 * This method unblocks an ideaDeveloper from a certain entity
	 * 
	 * @author Maryam
	 * 
	 * @param ideaDeveloper
	 *            The ideaDeveloper who will be unblocked
	 * @param entity
	 *            The entity that the ideaDeveloper will be unblocked from
	 * 
	 * 
	 */
	public void unblockIdeaDeveloper(IdeaDeveloper ideaDeveloper,
			Entities entity) {
		ideaDeveloper.blockedEnt.remove(entity);
		entity.blocked.add(ideaDeveloper);
		Log log = new Log("^ is un-blocked from ^.");
		log.ids = ideaDeveloper.id + "," + entity.id;
		log.types = "developer,entity";
		log.save();
	}

	/**
	 * @author: Andrew.el-dairy This method assings the start date to a plan
	 * 
	 * @param actionPlan
	 *            is the action plan which the dates will be assigned to
	 * @param sYear
	 *            year of the date
	 * @param sMonth
	 *            month of the date
	 * @param sDay
	 *            day of the date
	 * 
	 */
	public String setStartDate(ActionPlan actionPlan, int y, int sMonth, int d) {
		Date startDate = new Date((y - 1900), sMonth, d);
		java.util.Date date = new java.util.Date();
		java.sql.Date currentDate = new java.sql.Date(date.getTime());
		String result = "";
		if (startDate.after(actionPlan.endDate)) {
			result = ("End Date is before Start Date, end date is: " + DateFormat
					.getDateInstance(DateFormat.MEDIUM).format(
							actionPlan.endDate));
		} else if (actionPlan.endDate.before(currentDate)) {
			result = ("Plan has already expired on: " + DateFormat
					.getDateInstance(DateFormat.MEDIUM).format(
							actionPlan.endDate));
		} else if (startDate.before(currentDate)) {
			result = ("Start Date has already passed, today is: " + DateFormat
					.getDateInstance(DateFormat.MEDIUM).format(currentDate));
		} else {

			actionPlan.startDate = startDate;
			actionPlan.save();

			Log log = new Log("^ set a start date ^ ");
			log.ids = this.id + "," + actionPlan.id;
			log.types = "organizer,actionplan";
			log.save();
			List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
			 toBeNotified.addAll(actionPlan.volunteers);
			  //NOTIFICATION
			  
			  for (int i = 0; i < toBeNotified.size(); i++) { 
			  Notification.notify(" has  set the start date of the actionPlan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
					+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(i), this.ideaDeveloper, date); }
			result = "Done ..";
		}
		return result;

	}

	/**
	 * @author: Andrew.el-dairy This method assings the end date to a plan
	 * 
	 * @param actionPlan
	 *            is the action plan which the dates will be assigned to
	 * @param sYear
	 *            year of the date
	 * @param sMonth
	 *            month of the date
	 * @param sDay
	 *            day of the date
	 * 
	 */
	public String setEndDate(ActionPlan actionPlan, int y, int sMonth, int d) {
		Date endDate = new Date((y - 1900), sMonth, d);
		java.util.Date date = new java.util.Date();
		java.sql.Date currentDate = new java.sql.Date(date.getTime());
		String result = "";
		if (actionPlan.startDate.after(endDate)) {
			result = ("End Date is before Start Date,start date is: " + DateFormat
					.getDateInstance(DateFormat.MEDIUM).format(
							actionPlan.startDate));
		} else if (endDate.before(currentDate)) {
			result = ("Plan has already expired on: " + DateFormat
					.getDateInstance(DateFormat.MEDIUM).format(
							actionPlan.endDate));
		} else {

			actionPlan.endDate = endDate;
			actionPlan.save();

			Log log = new Log("^ set an end date ^ ");
			log.ids = this.id + "," + actionPlan.id;
			log.types = "organizer,actionplan";
			log.save();

			result = "Done ..";
			List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
			 toBeNotified.addAll(actionPlan.volunteers);
			  //NOTIFICATION
			  
			  for (int i = 0; i < toBeNotified.size(); i++) { 
			  Notification.notify(" has  set the end date of the actionPlan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
					+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(i), this.ideaDeveloper, date); }
		
		
		
		}
		
		
		
		
		return result;

	}

	/**
	 * @author: Andrew.el-dairy This method assings the end date to a plan
	 * 
	 * @param actionPlan
	 *            is the action plan which the dates will be assigned to
	 * @param ideaDev
	 *            the IdeaDeveloper which will be assigned to the plan
	 * 
	 * @return String: a string representing the result of success or failure
	 * 
	 */
	public String assignIdeaDevToPlan(ActionPlan actionPlan,
			IdeaDeveloper ideaDev) {
		java.util.Date date = new java.util.Date();
		java.sql.Date currentDate = new java.sql.Date(date.getTime());

		String result = "";
		Organization org = (Organization) Organization
				.find("id=?", actionPlan.organizationId).fetch().get(0);

		if (actionPlan.volunteers.contains(ideaDev)) {
			result = ("IdeaDeveloper already assigned to the plan..");
		} else if (actionPlan.endDate.before(currentDate)) {
			result = ("Plan is expired..");
		} else {
			IdeaDeveloper.joinOrganization(ideaDev, org);
			actionPlan.volunteers.add(ideaDev);
			ideaDev.volunteer.add(actionPlan);
			ideaDev.save();
			actionPlan.save();
			result = ideaDev.fullName + " has been Added";

			Log log = new Log("^ add IdeaDeveloper to a plan ^ ");
			log.ids = this.id + "," + actionPlan.id;
			log.types = "organizer,actionplan";
			log.save();
			 List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
			 toBeNotified.addAll(actionPlan.volunteers);
			 
			  //NOTIFICATION
			  
			  for (int y = 0; y < toBeNotified.size(); y++) { 
			  Notification.notify(" has  added an idea developer to the actionPlan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
					+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(y), this.ideaDeveloper, date); }

		}

		return result;

	}

	/**
	 * @author: Andrew.el-dairy This method assings one or more Ideas to an
	 *          exsisting or a new plan
	 * 
	 * @param actionPlan
	 *            is the action plan which the Ideas will be assigned to
	 * @param idea
	 *            is the list of ideas which will be assigned to the plan
	 * @return
	 * 
	 */
	public String assignIdeaToPlan(ActionPlan actionPlan, Idea idea) {
		java.util.Date date = new java.util.Date();
		java.sql.Date currentDate = new java.sql.Date(date.getTime());
		String result = "";
		Organization org = idea.orgWhereIdeaExist();

		if (actionPlan.endDate.before(currentDate)) {
			result = ("Plan has already expired..");
		} else {
			actionPlan.ideas.add(idea);
			idea.ideaPlan = actionPlan;
			actionPlan.save();
			idea.save();
			result = idea.title + " has been Added";
			
			 List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
			 toBeNotified.addAll(actionPlan.volunteers);
			  //NOTIFICATION
			  
			  for (int y = 0; y < toBeNotified.size(); y++) { 
			  Notification.notify(" has  added an idea to the actionPlan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
					+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(y), this.ideaDeveloper, date); }
			 

		}
		Log log = new Log("^ add Idea to a plan ^ ");
		log.ids = this.id + "," + actionPlan.id;
		log.types = "organizer,actionplan";
		log.save();

		return result;

	}

	/**
	 * allows organizer to relate action item to a speciefied topic
	 * 
	 * @author
	 * @param actionItem
	 *            the action item beeing related
	 * @param topic
	 *            the topic where the action item is being related to
	 * @return if successful "Item related to topic" , failure
	 *         "item already related" or "you don't manage this action item"
	 */
	// public String relateToTopic(ActionItem actionItem, Topic topic) {

	// if (managedActionItem.contains(actionItem)) {
	//
	// int index = managedActionItem.indexOf(actionItem);
	// ActionItem at = managedActionItem.get(index);
	//
	// Organization org = (Organization) Organization
	// .find("id=?", at.actionPlan.organizationId).fetch().get(0);
	// List<Topic> orgTopics = org.topics;
	//
	// if (at.topics.contains(topic)) {
	//
	// return "Item already related to topic";
	//
	// } else {
	//
	// for (int i = 0; i < orgTopics.size(); i++) {
	//
	// if (orgTopics.get(i) == topic) {
	//
	// at.topics.add(topic);
	// return "Item related to topic";
	//
	// }
	// }
	// }
	// } else {
	//
	// return "You dont manage this action item";
	//
	// }
	//
	// return "";

	// }

	public static boolean isManager(Long ideaDevoloperId, long topicId) {
		Organizer organizer = Organizer.find("ideaDeveloper.id=?",
				ideaDevoloperId).first();

		if (organizer == null) {
			return false;
		}
		Topic topic = Topic.findById(topicId);

		return organizer.managedTopics.contains(topic)
				|| organizer.manages.contains(topic.topicEnt);

	}
	/**
	 * This method allows an organizer to accept an idea developer's request to
	 * volunteer on a plan
	 * 
	 * @author Amr Gamal
	 * @param requestId
	 *            the Id of the request sent by the idea developer
	 * @return String this method returns the string "accepted" to be alerted to
	 *         the user
	 */

	public String approveRequest(long requestId) {
		Request requestToAccept = ((Request) Request.find("id=?", requestId)
				.first());
		// requestToAccept.accept2();
		return "accepted";

	}

	/**
	 * This method allows an organizer to reject an idea developer's request to
	 * volunteer on a plan
	 * 
	 * @Author Amr Gamal
	 * @param requestId
	 *            the Id of the request sent by the idea developer
	 * @return String this method returns the string "rejected" to be alerted to
	 *         the user
	 */

	public String rejectRequest(long requestId) {
		Request.reject(requestId);
		return "rejected";
	}
	/**
	 * @author: Andrew.el-dairy This method creates an action item
	 * 
	 * @param actionPlan
	 *            is the action plan which the dates will be assigned to
	 * @param title
	 * 				title of the item
	 * @param body
	 * 				body of the item
	 * @param startDate 
	 * 				start date of the item
	 * @param endDate 
	 * 				end date of the item
	 * 
	 * 
	 * @return String: a string representing the result of success or failure
	 * 
	 */
	public String CreateActionItem(ActionPlan actionPlan,String title, String body, Date startDate, Date endDate) {
		
		if(endDate.before(startDate)){return "Start Date is after End date";}

		ActionItem aItem= new ActionItem(title,body,startDate,endDate);
		  /*aItem.title=title;
		  aItem.body=body;
		  aItem.startDate=startDate;
		  aItem.endDate=endDate;*/
		String result="";
		
	/*	
		result  +=("start " + DateFormat.getDateInstance(DateFormat.MEDIUM).format(startDate));
		result  +=("end " + DateFormat.getDateInstance(DateFormat.MEDIUM).format(endDate));
	*/	
		//Organization org = (Organization) Organization.find("id=?", actionPlan.organizationId).fetch().get(0);
		aItem.actionPlan=actionPlan;
		actionPlan.actionItems.add(aItem);
		aItem.save();
		actionPlan.save();
		result+=aItem.title +" is added to the plan "+actionPlan.name;
			
		
		Log log = new Log("^ created action Item to a plan ^ ");
		log.ids = this.id + "," + actionPlan.id;
		log.types = "organizer,actionplan";
		log.save();
		
		List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
		toBeNotified.addAll(actionPlan.volunteers);
		  //NOTIFICATION
		java.util.Date date = new java.util.Date();

		  for (int i = 0; i < toBeNotified.size(); i++) { 
		  Notification.notify(" has  created an action item and added it to the actionPlan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
				+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(i), this.ideaDeveloper, date); }				
		return result;

	}
	/**
	 * @author: Andrew
	 *  This method relates a topic to an action item 
	 * 
	 * @param actionItem
	 *            the action item which the topic will be related to 
	 * @param topic
	 *            the topic to be related
	 * 
	 * @return String: a string representing the result of success or failure
	 * 
	 */
	public String relateItemToTopic(ActionItem actionItem, Topic topic) {
		java.util.Date date = new java.util.Date();
		java.sql.Date currentDate = new java.sql.Date(date.getTime());

		String result = "";
	

		 if (actionItem.endDate.before(currentDate)) {
			result = ("Item is expired on "+ DateFormat.getDateInstance(DateFormat.MEDIUM).format(actionItem.endDate));
		} else {
			actionItem.topics.add(topic);
			topic.actionItemTop.add(actionItem);
			result = actionItem.title + " has been related to topic :"+ topic.title;
			actionItem.save();
			topic.save();
			Log log = new Log("^ related ^ to ^");
			log.ids = this.id + "," + actionItem.id+","+topic.id;
			log.types = "organizer,actionitem,topic";
			log.save();
			ActionPlan actionPlan =actionItem.actionPlan;
			 List<IdeaDeveloper> toBeNotified = actionPlan.getPlanFollowers();
			 toBeNotified.addAll(actionPlan.volunteers);
			 
			  //NOTIFICATION
			  
			  for (int y = 0; y < toBeNotified.size(); y++) { 
			  Notification.notify(" has  related a topic to actionItem in the plan :<a href=\"http://localhost:9000/ActionPlanController/ActionPlanOrganizer?actionPlanId=="
					+ actionPlan.id + "\">" + actionPlan.name + "</a>", toBeNotified.get(y), this.ideaDeveloper, date); }

		}

		return result;

	}

}